package zero.tech.def.xe;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import zero.tech.core.util.EngineLogUtil;
import zero.tech.def.ClassManager;
import zero.tech.def.DataSettingTool;
import zero.tech.def.Describle;

public class DefDataTool {
	private static Map<String, List<Object>> baseDefsMap;

	private static DefDataTool defDataTool;

	private DefDataTool() throws Exception {
		// 加载配置类
		ClassManager.instance();
	}

	public static DefDataTool instance() {
		if (defDataTool == null) {
			try {
				defDataTool = new DefDataTool();
			} catch (Exception e) {
				EngineLogUtil.traceFull(e);
				throw new RuntimeException(e);
			}
		}
		return defDataTool;
	}

	// 重载数据
	public void load(String xml_package) throws Exception {
		baseDefsMap = new HashMap<String, List<Object>>();
		// 获得server路径下的所有子文件
		getFilesAllDefs(xml_package);
	}

	/**
	 * 加载文件
	 * 
	 * @param xmlRealPath 真实xml路径
	 */
	public List<Object> loadXml(InputStream inputStream) throws Exception {
		return DataSettingTool.parseByInputStream(inputStream);
	}

	/**
	 * 获得路径下的所有子文件
	 * 
	 * @return Set<File> 返回类型 @throws
	 */
	public void getFilesAllDefs(String xml_package) {
		// 获得路径下的所有子文件
		getDefXmlFile(xml_package);
	}

	/**
	 * 返回配置文件
	 * 
	 * @param webPath web中xml路径 @param xmlPath xml文件信息 @return Set<File>
	 *                返回所有配置文件 @throws
	 */
	public void getDefXmlFile(String xml_package) {
		scanPackagesFiles(xml_package);
	}

	private void scanPackagesFiles(String dirPath) {
		scanPackages(dirPath, true, Thread.currentThread().getContextClassLoader());
	}

	private void scanPackages(String dirPath, boolean recursive, ClassLoader classLoader) {
//		try {
//			Enumeration<URL> dirs = classLoader.getResources(dirPath);
//			while (dirs.hasMoreElements()) {
//				URL url = dirs.nextElement();
//				String protocol = url.getProtocol();
//				if ("file".equals(protocol)) {
//					String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
//					findAndAddClassesInPackageByFile(classLoader, filePath, recursive);
//				} else if ("jar".equals(protocol)) {
//					JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile();
//					Enumeration<JarEntry> entries = jar.entries();
//					while (entries.hasMoreElements()) {
//						JarEntry entry = entries.nextElement();
//						String name = entry.getName();
//						if (name.charAt(0) == '/') {
//							name = name.substring(1);
//						}
//						if (name.startsWith(dirPath)) {
//							int idx = name.lastIndexOf('/');
//							if (idx != -1) {
//								if ((idx != -1) || (recursive)) {
//									if ((name.endsWith(".xml")) && (!entry.isDirectory())) {
//										InputStream inputStream = null;
//										try {
//											inputStream = this.getClass().getResourceAsStream("/" + entry.getName());
//											List<Object> baseDefs = loadXml(inputStream);
//											pushListToDef(baseDefs);
//										} catch (Exception e) {
//											e.printStackTrace();
//										} finally {
//											if (inputStream != null) {
//												inputStream.close();
//											}
//										}
//									}
//								}
//							}
//						}
//					}
//				}
//			}
//		} catch (Exception e) {
//			e.printStackTrace();
//			System.exit(0);
//		}
		File file = new File(dirPath);
		if (file.isDirectory()) {
			File[] files = file.listFiles();
			if (files.length > 0) {
				for (File file1 : files) {
					String name = file1.getName();
					if (name.endsWith(".xml")) {
						FileInputStream inputStream = null;
						try {
							inputStream = new FileInputStream(file1);
							List<Object> baseDefs = loadXml(inputStream);
							pushListToDef(baseDefs);
						} catch (Exception e) {
							EngineLogUtil.traceFull(e);
						} finally {
							if (inputStream != null) {
								try {
									inputStream.close();
								} catch (IOException e) {
									EngineLogUtil.traceFull(e);
								}
							}
						}
					}
				}
			}
		}
	}

	public void findAndAddClassesInPackageByFile(ClassLoader classLoader, String dirPath, boolean recursive)
			throws Exception {
		File dir = new File(dirPath);
		if ((!dir.exists()) || (!dir.isDirectory())) {
			System.out.println("not found file in path " + dirPath);
			return;
		}
		File[] dirfiles = dir.listFiles(new PackageScanner2(recursive));
		for (File file : dirfiles) {
			if (file.isDirectory()) {
				findAndAddClassesInPackageByFile(classLoader, file.getAbsolutePath(), recursive);
			} else {
				if (file.exists()) {
					System.out.println("load " + file.getName());
					InputStream inputStream = null;
					try {
						inputStream = new FileInputStream(file);
						List<Object> baseDefs = loadXml(inputStream);
						pushListToDef(baseDefs);
					} catch (Exception e) {
						EngineLogUtil.traceFull(e);
					} finally {
						if (inputStream != null) {
							inputStream.close();
						}
					}
				}
			}
		}
	}

	private void pushListToDef(List<Object> baseDefs) {
		for (Object baseDef : baseDefs) {
			String clazzName = baseDef.getClass().getName();
			if (baseDefsMap.containsKey(clazzName)) {
				baseDefsMap.get(clazzName).add(baseDef);
			} else {
				List<Object> defs = new ArrayList<Object>();
				defs.add(baseDef);
				baseDefsMap.put(clazzName, defs);
			}
		}
	}

	public class PackageScanner2 implements FileFilter {
		private boolean recursive;

		PackageScanner2(boolean recursive) {
			this.recursive = recursive;
		}

		@Override
		public boolean accept(File file) {
			return (recursive && (file.isDirectory())) || (file.getName().endsWith(".xml"));
		}
	}

	/**
	 * 返回所有子文件
	 * 
	 * @param file 父类文件 @param files 配置文件集合 @throws
	 */
	public void getAllChildFile(File file, Set<File> files) {
		if (!file.exists()) {
			System.out.println(files + " is not exsit");
		}

		if (file.isFile()) {
			files.add(file);
		} else {
			File[] filechilds = file.listFiles();
			if (filechilds == null || filechilds.length == 0) {
//				System.out.println("config file has none");
				return;
			}
			for (File filechild : filechilds) {
				getAllChildFile(filechild, files);
			}
		}
	}

	public Map<String, List<Object>> getBaseObjectMap(String xml_package) throws Exception {
		if (baseDefsMap == null || baseDefsMap.size() == 0) {
			load(xml_package);
		}
		return baseDefsMap;
	}

	/**
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 * @throws InvocationTargetException
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException    获得类描述信息
	 * 
	 * @param clazz 传入的类 @return String[] 返回类名与类描述 @throws
	 */
	public static String getClassDescrible(Class<?> clazz) throws IllegalAccessException, IllegalArgumentException,
			InvocationTargetException, NoSuchMethodException, SecurityException {
		if (clazz == null) {
			System.out.println("类为空");
			return null;
		}
		boolean hasDescrible = false;
		String value = "";
		if (clazz.isAnnotationPresent(Describle.class)) {
			hasDescrible = true;
			Annotation annotation = clazz.getAnnotation(Describle.class);
			value = (String) annotation.annotationType().getDeclaredMethod("value").invoke(annotation);
		}
		if (!hasDescrible) {
			System.out.println(clazz.getName() + " has no @Describle annotation");
			return null;
		}

		return value;
	}
}
